/*
Copyright 2025 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta2

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
)

const (
	// VMProvisionedCondition documents the status of the provisioning VM implementing the InMemoryMachine.
	VMProvisionedCondition clusterv1.ConditionType = "VMProvisioned"

	// WaitingForClusterInfrastructureReason (Severity=Info) documents an InMemoryMachine VM waiting for the cluster
	// infrastructure to be ready.
	// WaitingForClusterInfrastructureReason = "WaitingForClusterInfrastructure".

	// WaitingControlPlaneInitializedReason (Severity=Info) documents an InMemoryMachine VM waiting
	// for the control plane to be initialized.
	WaitingControlPlaneInitializedReason = "WaitingControlPlaneInitialized"

	// WaitingForBootstrapDataReason (Severity=Info) documents an InMemoryMachine VM waiting for the bootstrap
	// data to be ready before starting to create the CloudMachine/VM.
	// WaitingForBootstrapDataReason = "WaitingForBootstrapData".

	// VMWaitingForStartupTimeoutReason (Severity=Info) documents a InMemoryMachine VM provisioning.
	VMWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"
)

const (
	// NodeProvisionedCondition documents the status of the provisioning of the node hosted on the InMemoryMachine.
	NodeProvisionedCondition clusterv1.ConditionType = "NodeProvisioned"

	// NodeWaitingForStartupTimeoutReason (Severity=Info) documents a InMemoryMachine Node provisioning.
	NodeWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"
)

const (
	// EtcdProvisionedCondition documents the status of the provisioning of the etcd member hosted on the InMemoryMachine.
	EtcdProvisionedCondition clusterv1.ConditionType = "EtcdProvisioned"

	// EtcdWaitingForStartupTimeoutReason (Severity=Info) documents a InMemoryMachine etcd pod provisioning.
	EtcdWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"
)

const (
	// APIServerProvisionedCondition documents the status of the provisioning of the APIServer instance hosted on the InMemoryMachine.
	APIServerProvisionedCondition clusterv1.ConditionType = "APIServerProvisioned"

	// APIServerWaitingForStartupTimeoutReason (Severity=Info) documents a InMemoryMachine API server pod provisioning.
	APIServerWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"
)

// DevMachine's conditions that apply to all the supported backends.

// DevMachine's Ready condition and corresponding reasons.
const (
	// DevMachineReadyCondition is true if
	// - The DevMachine's is using a docker backend and LoadBalancerAvailable is true.
	// - The DevMachine's is using an in memory backend and VMProvisioned, NodeProvisioned,
	//	 EtcdProvisioned (if present) and APIServerProvisioned (if present) conditions are true
	DevMachineReadyCondition = clusterv1.ReadyCondition

	// DevMachineReadyReason surfaces when the DevMachine readiness criteria is met.
	DevMachineReadyReason = clusterv1.ReadyReason

	// DevMachineNotReadyReason surfaces when the DevMachine readiness criteria is not met.
	DevMachineNotReadyReason = clusterv1.NotReadyReason

	// DevMachineReadyUnknownReason surfaces when at least one DevMachine readiness criteria is unknown
	// and no DevMachine readiness criteria is not met.
	DevMachineReadyUnknownReason = clusterv1.ReadyUnknownReason
)

// DevMachine's conditions that apply to the docker backend.

// ContainerProvisioned condition and corresponding reasons for a DevMachine's docker backend.
const (
	// DevMachineDockerContainerProvisionedCondition documents the status of the provisioning of the container
	// generated by a DevMachine's docker backend.
	//
	// NOTE as a difference from other providers, container provisioning and bootstrap are directly managed
	// by the DevMachine's docker backend controller (not by cloud-init).
	DevMachineDockerContainerProvisionedCondition string = "ContainerProvisioned"

	// DevMachineDockerContainerWaitingForClusterInfrastructureReadyReason documents the container for a DevMachine's docker backend waiting for the cluster
	// infrastructure to be ready.
	DevMachineDockerContainerWaitingForClusterInfrastructureReadyReason = clusterv1.WaitingForClusterInfrastructureReadyReason

	// DevMachineDockerContainerWaitingForControlPlaneInitializedReason documents a container for a DevMachine's docker backend waiting
	// for the control plane to be initialized.
	DevMachineDockerContainerWaitingForControlPlaneInitializedReason = clusterv1.WaitingForControlPlaneInitializedReason

	// DevMachineDockerContainerWaitingForBootstrapDataReason documents a container for a DevMachine's docker backend waiting for the bootstrap
	// data to be ready.
	DevMachineDockerContainerWaitingForBootstrapDataReason = clusterv1.WaitingForBootstrapDataReason

	// DevMachineDockerContainerProvisionedReason documents the container for a DevMachine's docker backend is provisioned.
	DevMachineDockerContainerProvisionedReason = clusterv1.ProvisionedReason

	// DevMachineDockerContainerNotProvisionedReason documents the container for a DevMachine's docker
	// backend is not provisioned.
	DevMachineDockerContainerNotProvisionedReason = clusterv1.NotProvisionedReason

	// DevMachineDockerContainerDeletingReason surfaces when the container for a DevMachine's docker
	// backend is deleting.
	DevMachineDockerContainerDeletingReason = clusterv1.DeletingReason
)

// BootstrapExecSucceeded condition and corresponding reasons for a DevMachine's docker backend.
const (
	// DevMachineDockerContainerBootstrapExecSucceededCondition provides an observation of the DevMachine's docker backend bootstrap process.
	// It is set based on successful execution of bootstrap commands and on the existence of
	// the /run/cluster-api/bootstrap-success.complete file.
	// The condition gets generated after ContainerProvisioned condition is True.
	//
	// NOTE as a difference from other providers, container provisioning and bootstrap are directly managed
	// by the DevMachine's docker backend controller (not by cloud-init).
	DevMachineDockerContainerBootstrapExecSucceededCondition string = "BootstrapExecSucceeded"

	// DevMachineDockerContainerBootstrapExecSucceededReason documents the container for a DevMachine's docker backend having
	// completed bootstrap exec commands.
	DevMachineDockerContainerBootstrapExecSucceededReason string = "Succeeded"

	// DevMachineDockerContainerBootstrapExecNotSucceededReason documents the container for a DevMachine's docker backend not having
	// completed bootstrap exec commands.
	DevMachineDockerContainerBootstrapExecNotSucceededReason string = "NotSucceeded"
)

// DevMachine's conditions that apply to the in memory backend.

// VirtualMachineProvisioned condition and corresponding reasons for a DevMachine's in memory backend.
const (
	// DevMachineInMemoryVMProvisionedCondition documents the status of the provisioning of a fake VM for a DevMachine's in memory backend.
	DevMachineInMemoryVMProvisionedCondition string = "VMProvisioned"

	// DevMachineInMemoryVMWaitingForClusterInfrastructureReason documents a fake VM for a DevMachine's in memory backend waiting for the cluster
	// infrastructure to be ready.
	DevMachineInMemoryVMWaitingForClusterInfrastructureReason = clusterv1.WaitingForClusterInfrastructureReadyReason

	// DevMachineInMemoryVMWaitingForControlPlaneInitializedReason documents a fake VM for a DevMachine's in memory backend waiting
	// for the control plane to be initialized.
	DevMachineInMemoryVMWaitingForControlPlaneInitializedReason = clusterv1.WaitingForControlPlaneInitializedReason

	// DevMachineInMemoryVMWaitingForBootstrapDataReason documents a fake VM for a DevMachine's in memory backend waiting for the bootstrap
	// data to be ready.
	DevMachineInMemoryVMWaitingForBootstrapDataReason = clusterv1.WaitingForBootstrapDataReason

	// DevMachineInMemoryVMWaitingForStartupTimeoutReason documents when the infrastructure for a fake VM for a DevMachine's in memory backend
	// is provisioning (it waits for a startup timeout).
	DevMachineInMemoryVMWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"

	// DevMachineInMemoryVMProvisionedReason documents when a fake VM for a DevMachine's in memory backend is fully provisioned.
	DevMachineInMemoryVMProvisionedReason = clusterv1.ProvisionedReason

	// DevMachineInMemoryVMInternalErrorReason surfaces unexpected error when reconciling a fake VM for a DevMachine's in memory backend.
	DevMachineInMemoryVMInternalErrorReason = clusterv1.InternalErrorReason
)

// NodeProvisioned condition and corresponding reasons for a DevMachine's in memory backend.
const (
	// DevMachineInMemoryNodeProvisionedCondition documents the status of the provisioning of the node hosted on the DevMachine's in memory backend.
	DevMachineInMemoryNodeProvisionedCondition string = "NodeProvisioned"

	// DevMachineInMemoryNodeWaitingForVMProvisionedReason documents a fake Node for a DevMachine's in memory backend waiting for the VM
	// to be provisioned.
	DevMachineInMemoryNodeWaitingForVMProvisionedReason = "WaitingForVMProvisioned"

	// DevMachineInMemoryNodeWaitingForStartupTimeoutReason documents when the fake Node for a DevMachine's in memory backend
	// is provisioning (it waits for a startup timeout).
	DevMachineInMemoryNodeWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"

	// DevMachineInMemoryNodeProvisionedReason documents when a fake Node for a DevMachine's in memory backend is fully provisioned.
	DevMachineInMemoryNodeProvisionedReason = clusterv1.ProvisionedReason

	// DevMachineInMemoryNodeInternalErrorReason surfaces unexpected error when reconciling a fake Node for a DevMachine's in memory backend.
	DevMachineInMemoryNodeInternalErrorReason = clusterv1.InternalErrorReason
)

// EtcdProvisioned condition and corresponding reasons for a DevMachine's in memory backend.
const (
	// DevMachineInMemoryEtcdProvisionedCondition documents the status of the etcd instance hosted on the DevMachine's in memory backend.
	DevMachineInMemoryEtcdProvisionedCondition string = "EtcdProvisioned"

	// DevMachineInMemoryEtcdWaitingForVMProvisionedReason documents a fake Etcd for a DevMachine's in memory backend waiting for the VM
	// to be provisioned.
	DevMachineInMemoryEtcdWaitingForVMProvisionedReason = "WaitingForVMProvisioned"

	// DevMachineInMemoryEtcdWaitingForNodeProvisionedReason documents a fake Etcd for a DevMachine's in memory backend waiting for the Node
	// to be provisioned.
	DevMachineInMemoryEtcdWaitingForNodeProvisionedReason = "WaitingForNodeProvisioned"

	// DevMachineInMemoryEtcdWaitingForStartupTimeoutReason documents when the fake Etcd for a DevMachine's in memory backend
	// is provisioning (it waits for a startup timeout).
	DevMachineInMemoryEtcdWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"

	// DevMachineInMemoryEtcdProvisionedReason documents when a fake Etcd for a DevMachine's in memory backend is fully provisioned.
	DevMachineInMemoryEtcdProvisionedReason = clusterv1.ProvisionedReason

	// DevMachineInMemoryEtcdInternalErrorReason surfaces unexpected error when reconciling a fake Etcd for a DevMachine's in memory backend.
	DevMachineInMemoryEtcdInternalErrorReason = clusterv1.InternalErrorReason
)

// APIServerProvisioned condition and corresponding reasons for a DevMachine's in memory backend.
const (
	// DevMachineInMemoryAPIServerProvisionedCondition documents the status of the provisioning of the APIServer instance hosted on the DevMachine's in memory backend.
	DevMachineInMemoryAPIServerProvisionedCondition string = "APIServerProvisioned"

	// DevMachineInMemoryAPIServerWaitingForVMProvisionedReason documents a fake APIServer for a DevMachine's in memory backend waiting for the VM
	// to be provisioned.
	DevMachineInMemoryAPIServerWaitingForVMProvisionedReason = "WaitingForVMProvisioned"

	// DevMachineInMemoryAPIServerWaitingForNodeProvisionedReason documents a fake APIServer for a DevMachine's in memory backend waiting for the Node
	// to be provisioned.
	DevMachineInMemoryAPIServerWaitingForNodeProvisionedReason = "WaitingForNodeProvisioned"

	// DevMachineInMemoryAPIServerWaitingForStartupTimeoutReason documents when the infrastructure for a fake APIServer for a DevMachine's in memory backend provisioning.
	DevMachineInMemoryAPIServerWaitingForStartupTimeoutReason = "WaitingForStartupTimeout"

	// DevMachineInMemoryAPIServerProvisionedReason documents when a fake APIServer for a DevMachine's in memory backend is fully provisioned.
	DevMachineInMemoryAPIServerProvisionedReason = clusterv1.ProvisionedReason

	// DevMachineInMemoryAPIServerInternalErrorReason surfaces unexpected error when reconciling a fake APIServer for a DevMachine's in memory backend.
	DevMachineInMemoryAPIServerInternalErrorReason = clusterv1.InternalErrorReason
)

// DevMachineSpec defines the desired state of DevMachine.
type DevMachineSpec struct {
	// providerID used to link this machine with the node hosted on it.
	// +optional
	// +kubebuilder:validation:MinLength=1
	// +kubebuilder:validation:MaxLength=512
	ProviderID string `json:"providerID,omitempty"`

	// backend defines backends for a DevMachine.
	// +required
	Backend DevMachineBackendSpec `json:"backend"`
}

// DevMachineBackendSpec defines backends for a DevMachine.
type DevMachineBackendSpec struct {
	// docker defines a backend for a DevMachine using docker containers.
	// +optional
	Docker *DockerMachineBackendSpec `json:"docker,omitempty"`

	// inMemory defines a backend for a DevMachine that runs in memory.
	// +optional
	InMemory *InMemoryMachineBackendSpec `json:"inMemory,omitempty"`
}

// DockerMachineBackendSpec defines a backend for a DevMachine using docker containers.
type DockerMachineBackendSpec struct {
	// customImage allows customizing the container image that is used for
	// running the machine
	// +optional
	CustomImage string `json:"customImage,omitempty"`

	// preLoadImages allows to pre-load images in a newly created machine. This can be used to
	// speed up tests by avoiding e.g. to download CNI images on all the containers.
	// +optional
	PreLoadImages []string `json:"preLoadImages,omitempty"`

	// extraMounts describes additional mount points for the node container
	// These may be used to bind a hostPath
	// +optional
	ExtraMounts []Mount `json:"extraMounts,omitempty"`

	// bootstrapped is true when the kubeadm bootstrapping has been run
	// against this machine
	//
	// Deprecated: This field will be removed in the next apiVersion.
	// When removing also remove from staticcheck exclude-rules for SA1019 in golangci.yml.
	// +optional
	Bootstrapped bool `json:"bootstrapped,omitempty"`

	// bootstrapTimeout is the total amount of time to wait for the machine to bootstrap before timing out.
	// The default value is 3m.
	// +optional
	BootstrapTimeout *metav1.Duration `json:"bootstrapTimeout,omitempty"`
}

// InMemoryMachineBackendSpec defines a backend for a DevMachine that runs in memory.
type InMemoryMachineBackendSpec struct {
	// vm defines the behaviour of the VM implementing the InMemoryMachine.
	VM *InMemoryVMSpec `json:"vm,omitempty"`

	// node defines the behaviour of the Node (the kubelet) hosted on the InMemoryMachine.
	Node *InMemoryNodeSpec `json:"node,omitempty"`

	// apiServer defines the behaviour of the APIServer hosted on the InMemoryMachine.
	APIServer *InMemoryAPIServerSpec `json:"apiServer,omitempty"`

	// etcd defines the behaviour of the etcd member hosted on the InMemoryMachine.
	Etcd *InMemoryEtcdSpec `json:"etcd,omitempty"`
}

// InMemoryVMSpec defines the behaviour of the VM implementing the InMemoryMachine.
type InMemoryVMSpec struct {
	// provisioning defines variables influencing how the VM implementing the InMemoryMachine is going to be provisioned.
	// NOTE: VM provisioning includes all the steps from creation to power-on.
	Provisioning CommonProvisioningSettings `json:"provisioning,omitempty"`
}

// InMemoryNodeSpec defines the behaviour of the Node (the kubelet) hosted on the InMemoryMachine.
type InMemoryNodeSpec struct {
	// provisioning defines variables influencing how the Node (the kubelet) hosted on the InMemoryMachine is going to be provisioned.
	// NOTE: Node provisioning includes all the steps from starting kubelet to the node become ready, get a provider ID, and being registered in K8s.
	Provisioning CommonProvisioningSettings `json:"provisioning,omitempty"`
}

// InMemoryAPIServerSpec defines the behaviour of the APIServer hosted on the InMemoryMachine.
type InMemoryAPIServerSpec struct {
	// provisioning defines variables influencing how the APIServer hosted on the InMemoryMachine is going to be provisioned.
	// NOTE: APIServer provisioning includes all the steps from starting the static Pod to the Pod become ready and being registered in K8s.
	Provisioning CommonProvisioningSettings `json:"provisioning,omitempty"`
}

// InMemoryEtcdSpec defines the behaviour of the etcd member hosted on the InMemoryMachine.
type InMemoryEtcdSpec struct {
	// provisioning defines variables influencing how the etcd member hosted on the InMemoryMachine is going to be provisioned.
	// NOTE: Etcd provisioning includes all the steps from starting the static Pod to the Pod become ready and being registered in K8s.
	Provisioning CommonProvisioningSettings `json:"provisioning,omitempty"`
}

// CommonProvisioningSettings holds parameters that applies to provisioning of most of the objects.
type CommonProvisioningSettings struct {
	// startupDuration defines the duration of the object provisioning phase.
	StartupDuration metav1.Duration `json:"startupDuration"`

	// startupJitter adds some randomness on StartupDuration; the actual duration will be StartupDuration plus an additional
	// amount chosen uniformly at random from the interval between zero and `StartupJitter*StartupDuration`.
	// NOTE: this is modeled as string because the usage of float is highly discouraged, as support for them varies across languages.
	StartupJitter string `json:"startupJitter,omitempty"`
}

// DevMachineStatus defines the observed state of DevMachine.
type DevMachineStatus struct {
	// conditions represents the observations of a DevMachine's current state.
	// Known condition types are Ready, NodeProvisioned, EtcdProvisioned, APIServerProvisioned, VMProvisioned,
	// ControlPlaneInitialized, BootstrapExecSucceeded, LoadBalancerAvailable, ContainerProvisioned and Paused.
	// +optional
	// +listType=map
	// +listMapKey=type
	// +kubebuilder:validation:MaxItems=32
	Conditions []metav1.Condition `json:"conditions,omitempty"`

	// initialization provides observations of the DevMachine initialization process.
	// NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial Machine provisioning.
	// +optional
	Initialization DevMachineInitializationStatus `json:"initialization,omitempty,omitzero"`

	// addresses contains the associated addresses for the dev machine.
	// +optional
	Addresses []clusterv1.MachineAddress `json:"addresses,omitempty"`

	// backend defines backends status for a DevMachine.
	// +optional
	Backend *DevMachineBackendStatus `json:"backend,omitempty"`

	// deprecated groups all the status fields that are deprecated and will be removed when all the nested field are removed.
	// +optional
	Deprecated *DevMachineDeprecatedStatus `json:"deprecated,omitempty"`
}

// DevMachineInitializationStatus provides observations of the DevMachine initialization process.
// +kubebuilder:validation:MinProperties=1
type DevMachineInitializationStatus struct {
	// provisioned is true when the infrastructure provider reports that the Machine's infrastructure is fully provisioned.
	// NOTE: this field is part of the Cluster API contract, and it is used to orchestrate initial Machine provisioning.
	// +optional
	Provisioned *bool `json:"provisioned,omitempty"`
}

// DevMachineBackendStatus define backend status for a DevMachine.
type DevMachineBackendStatus struct {
	// docker define backend status for a DevMachine for a machine using docker containers.
	// +optional
	Docker *DockerMachineBackendStatus `json:"docker,omitempty"`
}

// DockerMachineBackendStatus define backend status for a DevMachine for a machine using docker containers.
type DockerMachineBackendStatus struct {
	// loadBalancerConfigured denotes that the machine has been
	// added to the load balancer
	// +optional
	LoadBalancerConfigured bool `json:"loadBalancerConfigured"`
}

// DevMachineDeprecatedStatus groups all the status fields that are deprecated and will be removed when support for v1beta1 will be dropped.
// See https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20240916-improve-status-in-CAPI-resources.md for more context.
type DevMachineDeprecatedStatus struct {
	// v1beta1 groups all the status fields that are deprecated and will be removed when support for v1beta1 will be dropped.
	// +optional
	V1Beta1 *DevMachineV1Beta1DeprecatedStatus `json:"v1beta1,omitempty"`
}

// DevMachineV1Beta1DeprecatedStatus groups all the status fields that are deprecated and will be removed when support for v1beta1 will be dropped.
// See https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20240916-improve-status-in-CAPI-resources.md for more context.
type DevMachineV1Beta1DeprecatedStatus struct {
	// conditions defines current service state of the DevMachine.
	//
	// +optional
	//
	// Deprecated: This field is deprecated and is going to be removed when support for v1beta1 is dropped.
	Conditions clusterv1.Conditions `json:"conditions,omitempty"`
}

// +kubebuilder:resource:path=devmachines,scope=Namespaced,categories=cluster-api
// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels['cluster\\.x-k8s\\.io/cluster-name']",description="Cluster"
// +kubebuilder:printcolumn:name="Machine",type="string",JSONPath=".metadata.ownerReferences[?(@.kind==\"Machine\")].name",description="Machine object which owns with this DevMachine"
// +kubebuilder:printcolumn:name="ProviderID",type="string",JSONPath=".spec.providerID",description="Provider ID"
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.initialization.provisioned",description="Machine ready status"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of the DevMachine"

// DevMachine is the schema for the dev machine infrastructure API.
type DevMachine struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   DevMachineSpec   `json:"spec,omitempty"`
	Status DevMachineStatus `json:"status,omitempty"`
}

// GetV1Beta1Conditions returns the set of conditions for this object.
func (c *DevMachine) GetV1Beta1Conditions() clusterv1.Conditions {
	if c.Status.Deprecated == nil || c.Status.Deprecated.V1Beta1 == nil {
		return nil
	}
	return c.Status.Deprecated.V1Beta1.Conditions
}

// SetV1Beta1Conditions sets the conditions on this object.
func (c *DevMachine) SetV1Beta1Conditions(conditions clusterv1.Conditions) {
	if c.Status.Deprecated == nil {
		c.Status.Deprecated = &DevMachineDeprecatedStatus{}
	}
	if c.Status.Deprecated.V1Beta1 == nil {
		c.Status.Deprecated.V1Beta1 = &DevMachineV1Beta1DeprecatedStatus{}
	}
	c.Status.Deprecated.V1Beta1.Conditions = conditions
}

// GetConditions returns the set of conditions for this object.
func (c *DevMachine) GetConditions() []metav1.Condition {
	return c.Status.Conditions
}

// SetConditions sets conditions for an API object.
func (c *DevMachine) SetConditions(conditions []metav1.Condition) {
	c.Status.Conditions = conditions
}

// +kubebuilder:object:root=true

// DevMachineList contains a list of DevMachine.
type DevMachineList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []DevMachine `json:"items"`
}

func init() {
	objectTypes = append(objectTypes, &DevMachine{}, &DevMachineList{})
}
